local skynet = require "skynet"
local cluster = require "skynet.cluster"
local queue = require "skynet.queue"
local routerbase = require "routerbase"
local timetool = require "timetool"
local filelog = require "filelog"
local cs_t = queue()
local cs_r = queue()
local filename = "hbslnode.Router.lua"

require "hbslenum"

local Router = routerbase:new({
	idle_table_mng = nil,
	used_table_pool = {},
	table_index_begin = 90000,
	table_service_map = {},
	index_to_table = {},
	code_to_index = {},
	playermap = {},
	public_list = {},
	player_call_state = {},
	will_stop_server = false,
	})

function Router:init()
	self:add_func("nodemsg/nodecmd")
	self:add_func("nodemsg/noderequest")
end

function Router:forward(rid, tableservice, id)
	if self.playermap[rid] == nil then
		self.playermap[rid] = { table_service = tableservice , table_index = id, action_time = timetool.get_time() }
		self:notice_tableinfo_togatenode("role_enter_table", rid, skynet.getenv("nodename"), id)
	else
		self.playermap[rid].table_service = tableservice
		self.playermap[rid].table_index = id
		self:notice_tableinfo_togatenode("role_enter_table", rid, skynet.getenv("nodename"), id)
	end
end

function Router:unforward(rid, id)
	if self.playermap[rid] then
		if self.playermap[rid].table_index == id then
			self.playermap[rid] = nil
		end
	end
	if id ~= 0 then
		self:notice_tableinfo_togatenode("role_leave_table", rid, skynet.getenv("nodename"), id)
	end
end

function Router:clear_player_state(rid)
	if self.playermap[rid] then
		self.playermap[rid] = nil
	end
end

function Router:get_server_flag()
	return Router.will_stop_server
end

function Router:set_server_flag(flag)
	self.will_stop_server = flag	
	if self.will_stop_server == true then
		for index, table_service_obj in pairs(self.index_to_table) do
			if table_service_obj.table_service ~= nil then
				pcall(skynet.send, table_service_obj.table_service, "lua", "update_stop_server", flag)
			end
		end
	end
end

function Router:delete_table(id, rids)
	if id == nil or self.used_table_pool[id] ==  nil then return end
	local tableinfo = self.used_table_pool[id]
	local table_index = nil
	local code = tableinfo.create_table_id
	if tableinfo ~= nil then
		if tableinfo.create_table_id ~= nil then
			table_index = self.code_to_index[tableinfo.create_table_id]
			self.index_to_table[self.code_to_index[tableinfo.create_table_id]] = nil
			self.code_to_index[tableinfo.create_table_id] = nil
		end
		self.used_table_pool[id] = nil
	end
	if rids and type(rids) == "table" then
		for index, rid in ipairs(rids) do
			self:unforward(rid, id)
		end
	end
	if table_index and self.public_list[table_index] then
		self.public_list[table_index] = nil
	end
	return true
end

function Router:createtable(conf)
	local tableservice = self.idle_table_mng:create_service()
	local create_table_id
	local tableinfo
	if tableservice ~= nil then
		---生成随机码
		conf.table_index = self.table_index_begin
		self.table_index_begin = self.table_index_begin + 1
		local status, newcode = skynet.pcall(cluster.call, "hallnode", ".router", "create_table_code", skynet.getenv("nodename"), conf.table_index, conf.create_user_rid, conf)
		while (status == false) do
			skynet.sleep(100)
			status, newcode = skynet.pcall(cluster.call, "hallnode", ".router", "create_table_code", skynet.getenv("nodename"), conf.table_index, conf.create_user_rid, conf)
		end
		create_table_id = newcode
		self.used_table_pool[conf.table_index] = {}
		tableinfo = self.used_table_pool[conf.table_index]
		tableinfo.table_service = tableservice.service
		tableinfo.isdelete = false
		tableinfo.table_service_id = tableservice.id
		tableinfo.create_table_id = create_table_id
		conf.create_table_id = create_table_id
		conf.create_time = timetool.get_time()
		conf.uuid = conf.uuid .. skynet.getenv("nodename") .. "_" .. tostring(create_table_id) .. "_" .. tostring(conf.table_index) .. "_" .. tostring(timetool.get_time())
		local result = skynet.call(tableinfo.table_service, "lua", "start", conf, skynet.getenv("nodename"))
		if not result then
			filelog.sys_error("create_friend_table(:"..self.table_index_begin..") failed")
			pcall(skynet.kill, tableinfo.table_service)
			self.used_table_pool[conf.table_index] = nil
			self.index_to_table[conf.table_index] = nil
			self.code_to_index[create_table_id] = nil
			if self.table_index_begin > 1 then
				self.table_index_begin = self.table_index_begin - 1
			end
			return false, create_table_id, conf.table_index
		end	
	else
		filelog.sys_error("create_friend_table roomsvr's idle_table_mng not enough tableservice!")
		return false, create_table_id, conf.table_index
	end
	self.code_to_index[create_table_id] = conf.table_index
	self.index_to_table[conf.table_index] = {
		create_table_id = create_table_id,
    	table_service = tableinfo.table_service,
    	id = conf.table_index,
	}
	self.table_service_map[create_table_id] = {
		table_index = conf.table_index,
		table_service = tableinfo.table_service,
		create_rid = conf.create_user_rid,
		conf = conf,
		create_time = conf.create_time,
	}
	
	self.public_list[conf.table_index] = {
		table_index		= conf.table_index,
		table_code		= conf.create_table_id,
		max_player		= conf.max_player_num,
		cur_player		= 0,
		robot_num		= 0,
		create_time		= conf.create_time,
		create_rid 		= conf.create_user_rid,
		level_type		= conf.level_type,
		table_type		= conf.table_type,
		
	}
	return true, create_table_id, conf.table_index
end

function Router:notice_tableinfo_togatenode(msgname, rid, gamenode, table_index)
	skynet.pcall(cluster.call, "gatenode", ".router", msgname, rid, gamenode, table_index)
end


skynet.start(function() 
	skynet.dispatch("lua", 
		function(session, source, command, rid, ...)
			if Router.playermap[rid] and Router.playermap[rid].table_service then
				status, result = skynet.pcall(skynet.call, Router.playermap[rid].table_service, "lua", command, rid, ...)
				if status then
					if Router.playermap[rid] ~= nil and Router.playermap[rid].action_time ~= nil then
						Router.playermap[rid].action_time = timetool.get_time()
					end
				else
					filelog.sys_error("call table server failed!", command, rid)
					result = {retcode = EErrCode.ERR_SYSTEM_ERROR, retstr = "hbsl系统错误！"}
				end
				skynet.retpack(result)
			else
				if command == "entertable" then
					if Router.player_call_state[rid] == nil then Router.player_call_state[rid] = false end
					local f = Router.CMD[command]
					if f == nil then
						filelog.sys_error(filename.." CMD[command] is nil : ", rid, command)
						local result = false
					else
						if type(f) == "function" then
							if Router.player_call_state[rid] == false then
								Router.player_call_state[rid] = true
								status, result = skynet.pcall(f, rid, ... )
								if not status then
									filelog.sys_error(filename.." CMD[command] skynet.pcall failed : ", command, rid, result, ...)
								end
								Router.player_call_state[rid] = false
							end
						else
							filelog.print("role not in game table!")
							result = {retcode = EErrCode.ERR_INVALID_REQUEST, retstr = "玩家没在游戏中！"}
						end
					end
					if Router.player_call_state[rid] == false then
						skynet.retpack(result)
					end
				else
				    local f = Router.CMD[command]
					if f == nil then
						filelog.sys_error(filename.." CMD[command] is nil : ", rid, command)
						local result = false
					else
						if type(f) == "function" then
							status, result = skynet.pcall(f, rid, ... )
							if not status then
								filelog.sys_error(filename.." CMD[command] skynet.pcall failed : ", command, rid, result, ...)
							end
						else
							filelog.print("role not in game table!")
							result = {retcode = EErrCode.ERR_INVALID_REQUEST, retstr = "玩家没在游戏中！"}
						end
					end
					skynet.retpack(result)
				end
			end
		end)
	Router:init()
end)